﻿using System;
using System.Data;
#if NET7_0_OR_GREATER
using System.Data.Common;
#endif

namespace JESAI.DistributedLock.Postgres;

/// <summary>
/// 实现<see cref="IDistributedLockProvider"/>的<see cref="PostgresDistributedLoc"/>和
/// <see cref="IDistributedReaderWriterLockProvider"/>了解<see cref="PostgresDistributedReaderWwriterLock"/>。
/// <see cref="IDistributedReaderWriterLockProvider"/>了解<see cref="PostgresDistributedReaderWwriterLock"/>。
/// </summary>
public sealed class PostgresDistributedSynchronizationProvider : IDistributedLockProvider, IDistributedReaderWriterLockProvider
{
    private readonly Func<PostgresAdvisoryLockKey, PostgresDistributedLock> _lockFactory;
    private readonly Func<PostgresAdvisoryLockKey, PostgresDistributedReaderWriterLock> _readerWriterLockFactory;

    /// <summary>
    /// 使用提供的<paramref name="connectionString"/>和<paramref name="option"/>构造连接到Postgres的提供程序。
    /// </summary>
    public PostgresDistributedSynchronizationProvider(string connectionString, Action<PostgresConnectionOptionsBuilder>? options = null)
    {
        if (connectionString == null) { throw new ArgumentNullException(nameof(connectionString)); }

        this._lockFactory = key => new PostgresDistributedLock(key, connectionString, options);
        this._readerWriterLockFactory = key => new PostgresDistributedReaderWriterLock(key, connectionString, options);
    }

    /// <summary>
    /// 使用提供的<paramref name="connection"/>构造连接到Postgres的提供程序。
    /// </summary>
    public PostgresDistributedSynchronizationProvider(IDbConnection connection)
    {
        if (connection == null) { throw new ArgumentNullException(nameof(connection)); }

        this._lockFactory = key => new PostgresDistributedLock(key, connection);
        this._readerWriterLockFactory = key => new PostgresDistributedReaderWriterLock(key, connection);
    }

#if NET7_0_OR_GREATER
    /// <summary>
    /// 使用提供的<paramref name="dbDataSource"/>和<paramref name="options"/>构造连接到Postgres的提供程序。
    /// 
    /// 与连接多路复用不兼容。
    /// </summary>
    public PostgresDistributedSynchronizationProvider(DbDataSource dbDataSource, Action<PostgresConnectionOptionsBuilder>? options = null)
    {
        if (dbDataSource == null) { throw new ArgumentNullException(nameof(dbDataSource)); }

        this._lockFactory = key => new PostgresDistributedLock(key, dbDataSource, options);
        this._readerWriterLockFactory = key => new PostgresDistributedReaderWriterLock(key, dbDataSource, options);
    }
#endif

    /// <summary>
    /// 使用提供的<paramref name="key"/>创建<see cref="PostgresDistributedLock"/>。
    /// </summary>
    public PostgresDistributedLock CreateLock(PostgresAdvisoryLockKey key) => this._lockFactory(key);

    IDistributedLock IDistributedLockProvider.CreateLock(string name) =>
        this.CreateLock(new PostgresAdvisoryLockKey(name, allowHashing: true));

    /// <summary>
    /// 使用提供的<paramref name="key"/>创建<see cref="PostgresDistributedReaderWriterLock"/>。
    /// </summary>
    public PostgresDistributedReaderWriterLock CreateReaderWriterLock(PostgresAdvisoryLockKey key) => this._readerWriterLockFactory(key);

    IDistributedReaderWriterLock IDistributedReaderWriterLockProvider.CreateReaderWriterLock(string name) =>
        this.CreateReaderWriterLock(new PostgresAdvisoryLockKey(name, allowHashing: true));
}